#include <iostream>
#include <unistd.h>
#include <string>
#include <pthread.h>
#include <assert.h>
#include <cstdio>

using std::cout;
using std::endl;
using std::string;

// // 多线程抢票, 使用全局锁来保护临界资源   使用全局锁
// pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; // 使用宏来初始化全局锁
// int tickets = 10000;   // 票 -> 全局性的,对于线程而言是共享的
// void* getTickers(void* args)
// {
//     while (true)
//     {
//         // 上锁
//         pthread_mutex_lock(&mtx);

//         // 访问临界区
//         if (tickets > 0) // 证明有票
//         {
//             usleep(1000);
//             printf("%s: %d\n", (char*)args, tickets);
//             tickets--;
//             // 解锁
//             pthread_mutex_unlock(&mtx);
//         }
//         else
//         {
//             pthread_mutex_unlock(&mtx);  // 没有票了,这里也需要解锁一下
//             break;
//         }
//     }
    
//     usleep(2000);  // 抢完票,执行后续的逻辑
// }

// int main()
// {
//     pthread_t t1, t2, t3;
//     pthread_create(&t1, nullptr, getTickers, (void*)"线程1");
//     pthread_create(&t2, nullptr, getTickers, (void*)"线程2");
//     pthread_create(&t3, nullptr, getTickers, (void*)"线程3");

//     pthread_join(t1, nullptr);
//     pthread_join(t2, nullptr);
//     pthread_join(t3, nullptr);
//     return 0;
// }



// // 多线程抢票，使用局部锁
// int tickets = 10000;  // 票数
// #define THREAD_NUM 5  // 抢票的线程数
// class ThreadDate
// {
// public:
//     ThreadDate(string name, pthread_mutex_t* mtx)
//         :_name(name)
//         ,_mtx(mtx)
//     {}

// public:
//     string _name;
//     pthread_mutex_t* _mtx;
// };

// void* getTickets(void* args)
// {
//     ThreadDate* td = (ThreadDate*)args;
//     while (true)
//     {
//         // 上锁
//         pthread_mutex_lock(td->_mtx);
//         if (tickets > 0)
//         {
//             usleep(1000);
//             printf("%s: %d\n", td->_name.c_str(), tickets);
//             tickets--;
//             pthread_mutex_unlock(td->_mtx);  // 解锁
//         }
//         else
//         {
//             pthread_mutex_unlock(td->_mtx);
//             break;
//         }
//     }

//     delete td;
//     return nullptr;
// }

// int main()
// {
//     time_t start = time(nullptr);

//     pthread_t t[THREAD_NUM];   // 创建线程id
//     pthread_mutex_t mtx;   // 创建局部锁
//     pthread_mutex_init(&mtx, nullptr);  // 初始化局部锁

//     // 创建线程抢票
//     for (int i = 0; i < THREAD_NUM; i++)
//     {
//         string name = "thead ";
//         name += std::to_string(i);
//         ThreadDate* td = new ThreadDate(name, &mtx);
//         pthread_create(t + i, nullptr, getTickets, (void*)td);
//     }

//     for (int i = 0; i < THREAD_NUM; i++)
//     {
//         pthread_join(t[i], nullptr);
//     }

//     pthread_mutex_destroy(&mtx); // 销毁锁

//     time_t end = time(nullptr);
//     cout << "cast: " << (int)(end - start) << endl;
//     return 0;
// }



// 线程同步  使用主线程来控制新线程,但一般不这么玩,见明天的生产消费模型
#define NUM 4  // 线程个数
volatile bool quit = false;  //退出的标记位
typedef void (*func_t)(const string& name, pthread_mutex_t* mtx, pthread_cond_t* cond); // 函数执行方法

class ThreadData
{
public:
    ThreadData(const string& name, func_t func, pthread_mutex_t* mtx, pthread_cond_t* cond)
        :_name(name)
        ,_func(func)
        ,_mtx(mtx)
        ,_cond(cond)
    {}
public:
    string _name;
    func_t _func;
    pthread_mutex_t* _mtx;
    pthread_cond_t* _cond;
};

// 不同的线程执行方法
void func1(const string& name, pthread_mutex_t* mtx, pthread_cond_t* cond)
{
    while (!quit)
    {
        pthread_mutex_lock(mtx);
        //if (临界资源是否就绪)
        pthread_cond_wait(cond, mtx);
        cout << name << " running --- a ----- 播放" << endl;
        pthread_mutex_unlock(mtx);
    }
}

void func2(const string& name, pthread_mutex_t* mtx, pthread_cond_t* cond)
{
    while (!quit)
    {
        pthread_mutex_lock(mtx);
        //if (临界资源是否就绪)
        pthread_cond_wait(cond, mtx);
        cout << name << " running --- b ----- 下载" << endl;
        pthread_mutex_unlock(mtx);
    }
}

void func3(const string& name, pthread_mutex_t* mtx, pthread_cond_t* cond)
{
    while (!quit)
    {
        pthread_mutex_lock(mtx);
        //if (临界资源是否就绪)
        pthread_cond_wait(cond, mtx);
        cout << name << " running --- c ----- 扫描" << endl;
        pthread_mutex_unlock(mtx);
    }
}

void func4(const string& name, pthread_mutex_t* mtx, pthread_cond_t* cond)
{
    while (!quit)
    {
        pthread_mutex_lock(mtx);
        //if (临界资源是否就绪)
        pthread_cond_wait(cond, mtx);
        cout << name << " running --- d ----- 打印" << endl;
        pthread_mutex_unlock(mtx);
    }
}

void* Entry(void* args)
{
    ThreadData* td = (ThreadData*)args;
    td->_func(td->_name, td->_mtx, td->_cond);
    delete td;

    return nullptr;
}
int main()
{
    pthread_mutex_t mtx;  // 创建锁
    pthread_cond_t cond;  // 创建条件变量

    // 初始化
    pthread_mutex_init(&mtx, nullptr);
    pthread_cond_init(&cond, nullptr);

    // 创建线程id
    pthread_t tid[NUM];

    // 创建不同的执行方法
    func_t funcs[NUM] = {func1, func2, func3, func4};

    // 创建多线程
    for (int i = 0; i < NUM; i++)
    {
        string name = "Thread ";
        name += std::to_string(i);  // 线程名称
        ThreadData* td = new ThreadData(name, funcs[i], &mtx, &cond);
        pthread_create(tid + i, nullptr, Entry, (void*)td);
    }

    sleep(3);

    // 控制新线程
    int cnt = 10;
    while(cnt)
    {
        cout << "resume thread run code ..." << cnt-- << endl;
        // pthread_cond_signal(&cond);   // 随机唤醒一个线程
        pthread_cond_broadcast(&cond);     // 唤醒所有线程
        sleep(1);
    }

    cout << "ctrl done .." << endl;
    quit = true;
    pthread_cond_broadcast(&cond);  // 唤醒所有线程

    // 线程回收
    for (int i = 0; i < NUM; i++)
    {
        pthread_join(tid[i], nullptr);
        cout << tid[i] << ": " << "quit" << endl;
    }

    // 销毁锁和条件变量
    pthread_mutex_destroy(&mtx);
    pthread_cond_destroy(&cond);
    return 0;
}
